#![allow(warnings)]
use std::{rc::Rc, cell::RefCell, sync::Arc};

use crate::classfile::MemberInfo;

use super::{class::Class, access_flags::{ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC, ACC_VOLATILE, ACC_TRANSIENT, ACC_ENUM}, class_name_helper::to_class_name};

#[derive(Default)]
pub struct Field {
    access_flags: u16, // 访问标志
    name: String, // 字段名称
    descriptor: String, // 描述符
    signature: String, 
    annotation_data: Vec<u8>, // RuntimeVisibleAnnotations_attribute
    class: Option<Arc<Class>>,
    // class_member ↑
    const_value_index: usize, // 常量值在常量池中的索引
    slot_id: usize, // 
}

// class_member
impl Field {
    // 复制字段信息，访问标志、字段名称、描述符
    pub fn copy_member_info(&mut self, member_info: &MemberInfo) {
        self.access_flags = member_info.access_flags();
        self.name = member_info.name();
        self.descriptor = member_info.descriptor();
    }

    pub fn is_public(&self) -> bool {
        0 != self.access_flags & ACC_PUBLIC
    }

    pub fn is_private(&self) -> bool {
        0 != self.access_flags & ACC_PRIVATE
    }

    pub fn is_protected(&self) -> bool {
        0 != self.access_flags & ACC_PROTECTED
    }

    pub fn is_static(&self) -> bool {
        0 != self.access_flags & ACC_STATIC
    }

    pub fn is_final(&self) -> bool {
        0 != self.access_flags & ACC_FINAL
    }

    pub fn is_synthetic(&self) -> bool {
        0 != self.access_flags & ACC_SYNTHETIC
    }

    // getters
    pub fn get_access_flags(&self) -> u16 {
        self.access_flags
    }

    pub fn get_name(&self) -> String {
        self.name.clone()
    }

    pub fn get_descriptor(&self) -> String {
        self.descriptor.clone()
    }

    pub fn get_signature(&self) -> String {
        self.signature.clone()
    }

    pub fn get_annotation_data(&self) -> &Vec<u8> {
        &self.annotation_data
    }

    pub fn get_class(&self) -> Arc<Class> {
        self.class.clone().unwrap()
    }

    pub fn get_class_ptr(&self) -> Arc<Class> {
        self.class.clone().unwrap()
    }

    // 是否能访问 jvms 5.4.4
    pub fn is_accessible_to(&self, d: Arc<Class>) -> bool {
        // public
        if self.is_public() {
            return true;
        }
        let c = self.get_class();
        // protected仅允许子类和同包下的文件访问
        if self.is_protected() {
            return Arc::ptr_eq(&c, &d) || d.is_sub_class_of(&c) || c.get_package_name() == d.get_package_name();
        }
        // 默认访问权，仅同包下文件可访问
        if !self.is_private() {
            return c.get_package_name() == d.get_package_name();
        }
        // 是否指向统一class
        Arc::ptr_eq(&c, &d)
    }
}

impl Field  {
    // 有class_file中的field字段生成
    pub fn new_fields(class: Arc<Class>, cf_fields: &Vec<MemberInfo>) -> Vec<Arc<Field>> {
        cf_fields.iter().map(|cf_field| {
            let mut field = Field::default();
            field.class = Some(class.clone());
            field.copy_member_info(cf_field);
            field.copy_attributes(cf_field);
            Arc::new(field)
        }).collect()
    }

    // 从字段属性表中读取constValueIndex
    pub fn copy_attributes(&mut self, member_info: &MemberInfo) {
        if let Some(val_attr) = member_info.constant_value_attribute() {
            self.const_value_index = val_attr.constant_value_index();
        }
    }

    pub fn is_volatile(&self) -> bool {
        0 != self.access_flags & ACC_VOLATILE
    }

    pub fn is_transient(&self) -> bool {
        0 != self.access_flags & ACC_TRANSIENT
    }

    pub fn is_enum(&self) -> bool {
        0 != self.access_flags & ACC_ENUM
    }

    pub fn get_const_value_index(&self) -> usize {
        self.const_value_index
    }

    pub fn set_slot_id(&mut self, id: usize) {
        self.slot_id = id;
    }

    pub fn get_slot_id(&self) -> usize {
        self.slot_id
    }

    pub fn is_long_or_double(&self) -> bool {
        match &self.descriptor[..] {
            "J" | "D" => true,
            _ => false
        }
    }

    // reflection
    pub fn get_type(&self) -> Arc<Class> {
        let class_name = to_class_name(&self.descriptor);
        self.class.as_ref().unwrap().get_class_loader().unwrap().lock().unwrap().load_class(class_name)
    }
}